#pragma once

#include <rclcpp/rclcpp.hpp>
#include <memory>
#include <vector>
#include <QWidget>
#include <QListWidget>
#include <QPushButton>
#include <QTimer>
#include <QVBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <rviz_common/panel.hpp>
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <navigation/srv/rviz2_nav.hpp>
#include <navigation/rviz2_gui/rviz2_const.hpp>
#include <navigation/msg/targets_list.hpp>
#include <std_msgs/msg/string.hpp>
#include <std_msgs/msg/bool.hpp>
#include <std_srvs/srv/set_bool.hpp>
#include <thread>
#include <atomic>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QFileDialog>

using navigation::srv::Rviz2Nav;

class Rviz2GuiPanel : public rviz_common::Panel {
    Q_OBJECT
public:
    explicit Rviz2GuiPanel(QWidget* parent = nullptr);
    virtual ~Rviz2GuiPanel() override;

    void onInitialize() override;

protected Q_SLOTS:
    void updateTargetList();
    void onStartClicked();
    void onPauseClicked();
    void onListOrderChanged(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row);
    void onMapClicked(const geometry_msgs::msg::PoseStamped& pose);
    void onRemoveTarget(int index);

private:
    void call_service(Rviz2ConnecterType type, bool need_resp = false);
    Rviz2Nav::Response call_service_async(std::shared_ptr<Rviz2Nav::Request> req, bool need_resp = false);
    void subscribe_target_names();
    void subscribe_goal_pose();
    void request_maps_dir_path();

    std::shared_ptr<rclcpp::Node> node_;
    std::thread spin_thread_;
    rclcpp::Client<Rviz2Nav>::SharedPtr client_;
    QListWidget* target_list_;
    QPushButton* toggle_btn_;
    QPushButton* save_btn_;
    QPushButton* load_btn_;
    QLabel* status_label_;
    QTimer* update_timer_;
    std::vector<std::string> last_names_;
    std::vector<std::string> current_names_;
    std::atomic<bool> controller_is_paused_ = true;
    rclcpp::Subscription<navigation::msg::TargetsList>::SharedPtr names_sub_;
    rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr goal_sub_;
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr map_file_path_sub_;
    std::string maps_dir_path_;
    QPushButton* adjuster_btn_;
    bool adjuster_paused_ = true;
    rclcpp::Client<std_srvs::srv::SetBool>::SharedPtr adjuster_client_;
    rclcpp::Subscription<std_msgs::msg::Bool>::SharedPtr controller_is_paused_sub_;
};
